package app.server.project.main.service.service.upay;

import app.server.project.core.constants.TcpCmd;
import app.server.project.core.exception.SysError;
import app.server.project.core.util.AssertUtil;
import app.server.project.core.util.MathUtil;
import app.server.project.core.websocket.WSMgr;
import app.server.project.main.service.bo.event.ConsumeRaceValEvent;
import app.server.project.main.service.db.dao.user.BlockTransactionDao;
import app.server.project.main.service.db.dao.user.UserInfoDao;
import app.server.project.main.service.db.dao.user.UserUSDTDao;
import app.server.project.main.service.db.entity.cfg.RaceCfgEntity;
import app.server.project.main.service.db.entity.user.BlockTransactionEntity;
import app.server.project.main.service.db.entity.user.UserInfoEntity;
import app.server.project.main.service.db.entity.user.UserWithDrawDetailEntity;
import app.server.project.main.service.dto.BalanceDto;
import app.server.project.main.service.dto.upay.AddTxReq;
import app.server.project.main.service.dto.upay.USDTWithDrawReq;
import app.server.project.main.service.service.LockService;
import app.server.project.main.service.service.race.CoinType;
import app.server.project.main.service.service.race.DetailType;
import app.server.project.main.service.service.withdraw.WithDrawStatus;
import cn.hutool.core.util.IdUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;

import static app.server.project.main.service.service.upay.UPayType.*;

@RequiredArgsConstructor
@Service
public class BalanceService {


    private final ApplicationEventPublisher applicationEventPublisher;

    private final UserUSDTDao userUSDTDao;
    private final LockService lockService;
    private final UserInfoDao userInfoDao;
    private final BlockTransactionDao blockTransactionDao;

    public BalanceDto getBalance(long userId) {
        var db = this.userUSDTDao.getDataBy(userId);
        return BalanceDto.of(String.valueOf(db.getUsdVal()), String.valueOf(U_Rate));
    }

    public void addBalance(long userId, long val) {
        var db = this.userUSDTDao.getDataBy(userId);
        db.addUsdVal(val);
        WSMgr.push(userId, TcpCmd.USDVal, this.getBalance(userId));
    }

    public void pushBalance(long userId) {
        WSMgr.push(userId, TcpCmd.USDVal, this.getBalance(userId));
    }

    public void cmsAddBalance(AddTxReq req) {
        this.addBalance(req.getUserId(), req.getAmount());
        //检查交易是否被处理
        var transaction = this.blockTransactionDao.getBlockTransactionBy(UPayType.Tron, req.getTransactionId());
        if (transaction == null) {
            transaction = BlockTransactionEntity.of(req.getTransactionId(), req.getUserId(), req.getAmount(), UPayType.Tron);
            this.blockTransactionDao.saveOrUpdate(transaction);
        }
    }

    public boolean subBalance(long userId, long val) {
        var db = this.userUSDTDao.getDataBy(userId);
        var flag = db.consume(val);
        if (flag) {
            WSMgr.push(userId, TcpCmd.USDVal, this.getBalance(userId));
        }
        return flag;
    }

    public void withdraw(USDTWithDrawReq req, long userId) {


        var lock = this.lockService.getLock(userId);
        synchronized (lock) {
            var db = this.userUSDTDao.getDataBy(userId);
            //检查提现金额
            AssertUtil.isTrue(db.getUsdVal() > 10 * U_Rate, SysError.WithDraw_Amount);
            var money = db.getUsdVal();
            if (!db.consume(db.getUsdVal())) return;
            RaceCfgEntity cfg = new RaceCfgEntity();
            cfg.setId(CoinType.USDT_COIN);
            cfg.setName("USDT");
            cfg.setRate(U_Rate);

            WSMgr.push(userId, TcpCmd.USDVal, this.getBalance(userId));

            //添加审批提现明细
            var detail = UserWithDrawDetailEntity.of(IdUtil.getSnowflakeNextId());
            UserInfoEntity userInfoEntity = this.userInfoDao.getUserInfoById(userId);

            detail.setName(cfg.getName());
            detail.setNick(userInfoEntity.getNick());
            detail.setRaceId(cfg.getId());
            detail.setRate(cfg.getRate());
            detail.setStatus(WithDrawStatus.Apply);
            detail.setWalletLocation(req.getWalletUrl());
            detail.setUserId(userId);

            detail.setVal(money);
            detail.setMoney(MathUtil.getNumFormat(money, cfg.getRate()));
            switch (req.getBlockType()) {
                case UPayType.Tron: {
                    detail.setBlockType("Tron");
                }
                break;
                case Ton: {
                    detail.setBlockType("Ton");
                }
                break;
                case BSC: {
                    detail.setBlockType("BSC");
                }
                break;
            }
            //添加用户提现明细
            var event = ConsumeRaceValEvent.of(detail.getUserId(), cfg, detail.getVal(), DetailType.Withdrawal.getType(), detail.getId());

            event.setBlockType(req.getBlockType());
            this.applicationEventPublisher.publishEvent(event);
        }
    }
}
